<template>
    <div class="collaborative-editor-container">
      <!-- 当前用户信息 -->
      <div class="user-info">
        <div class="username" :style="{ color: user.color }">
          {{ user.name }}
          <img class="user-avatar" :src="user.icon" :alt="user.name" />
        </div>
      </div>
  
      <!-- 协同用户列表 -->
      <div class="collaborators">
        <div 
          v-for="(collaborator, id) in collaborators" 
          :key="id"
          class="collaborator"
          :style="{ color: collaborator.user?.color }"
        >
          <img 
            class="collaborator-avatar"
            :src="collaborator.user?.icon" 
            :alt="collaborator.user?.name"
          />
          {{ collaborator.user?.name }}
        </div>
      </div>
  
      <!-- 编辑器区域 -->
      <div class="editor-container" ref="editorContainer">
        <textarea
          class="editor"
          :value="value"
          @input="handleChange"
          @keyup="updateCursorPosition"
          @click="updateCursorPosition"
          @mousemove="updateCursorPosition"
          ref="editor"
          placeholder="开始协同编辑..."
        ></textarea>
        
        <!-- 其他用户的光标指示器 -->
        <div 
          v-for="(collaborator, id) in collaborators" 
          :key="id"
          class="cursor-indicator"
          :style="getCursorStyle(collaborator)"
        >
          <div class="cursor-label" :style="{ backgroundColor: collaborator.user?.color }">
            {{ collaborator.user?.name }}
          </div>
        </div>
      </div>
    </div>
  </template>
  
  <script setup lang="ts">
  import { ref, onMounted, onUnmounted, computed } from 'vue'
  import * as Y from 'yjs'
  import { IndexeddbPersistence } from 'y-indexeddb'
  import { WebsocketProvider } from "y-websocket"
  
  // 初始化 Yjs 文档
  const ydoc = new Y.Doc()
  const ytext = ydoc.getText('content')
  
  // DOM 引用
  const editor = ref<HTMLTextAreaElement | null>(null)
  const editorContainer = ref<HTMLDivElement | null>(null)
  
  // 响应式数据
  const value = ref('')
  const user = ref({
    name: '',
    color: '',
    icon: '',
    cursorPos: 0
  })
  const collaborators = ref<Record<number, any>>({})
  const cursorPositions = ref<Record<number, number>>({})
  
  // 创建WebSocket连接
  const provider = new WebsocketProvider(
    'ws://localhost:1234',
    'room1',
    ydoc
  )
  
  // 生成随机用户信息
  const generateUserInfo = () => {
    const name = '用户-' + Math.random().toString(36).substring(2, 8)
    const color = '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')
    const icon = `https://robohash.org/${encodeURIComponent(name)}?set=set1&size=100x100`
    
    return { name, color, icon }
  }
  
  // 设置当前用户信息
  const { name, color, icon } = generateUserInfo()
  user.value = { name, color, icon, cursorPos: 0 }
  provider.awareness.setLocalStateField("user", user.value)
  
  // 计算字符宽度（用于光标定位）
  const charWidth = computed(() => {
    if (!editor.value) return 8 // 默认值
    const tempSpan = document.createElement('span')
    tempSpan.textContent = 'W' // 'W'是典型宽字符
    tempSpan.style.visibility = 'hidden'
    tempSpan.style.position = 'absolute'
    tempSpan.style.font = window.getComputedStyle(editor.value).font
    document.body.appendChild(tempSpan)
    const width = tempSpan.getBoundingClientRect().width
    document.body.removeChild(tempSpan)
    return width || 8
  })
  
  // 计算行高度
  const lineHeight = computed(() => {
    if (!editor.value) return 18 // 默认值
    return parseInt(window.getComputedStyle(editor.value).lineHeight) || 18
  })
  
  // 处理编辑器内容变化
  const handleChange = (e: Event) => {
    const target = e.target as HTMLTextAreaElement
    const newValue = target.value
    
    // 使用Yjs进行协同编辑
    ytext.delete(0, ytext.length)
    ytext.insert(0, newValue)
    value.value = newValue
    updateCursorPosition()
  }
  
  // 更新光标位置
  const updateCursorPosition = () => {
    if (!editor.value) return
    
    const pos = editor.value.selectionStart
    user.value.cursorPos = pos
    provider.awareness.setLocalStateField("user", user.value)
    
    // 计算并发布光标位置
    const textBeforeCursor = value.value.substring(0, pos)
    const lines = textBeforeCursor.split('\n')
    const currentLine = lines[lines.length - 1]
    
    // 这里可以添加更精确的光标位置计算逻辑
    cursorPositions.value[provider.awareness.clientID] = pos
  }
  
  // 获取光标样式
  const getCursorStyle = (collaborator: any) => {
    if (!editor.value || !editorContainer.value) return {}
    
    const pos = collaborator.user?.cursorPos || 0
    const textBeforeCursor = value.value.substring(0, pos)
    const lines = textBeforeCursor.split('\n')
    const lineNum = lines.length
    const currentLine = lines[lines.length - 1]
    
    // 计算光标位置
    const top = (lineNum) * lineHeight.value
    const left = currentLine.length * charWidth.value
    
    return {
      top: `${top}px`,
      left: `${left}px`,
      backgroundColor: collaborator.user?.color
    }
  }
  
  // 更新协作用户列表
  const updateCollaborators = () => {
    const states = provider.awareness.getStates()
    const newCollaborators: Record<number, any> = {}
    const newCursorPositions: Record<number, number> = {}
    
    states.forEach((state, clientId) => {
      if (state.user) {
        newCollaborators[clientId] = state
        if (state.user.cursorPos !== undefined) {
          newCursorPositions[clientId] = state.user.cursorPos
        }
      }
    })
    
    collaborators.value = newCollaborators
    cursorPositions.value = newCursorPositions
  }
  
  // 初始化 IndexedDB 持久化
  const persistence = new IndexeddbPersistence('testdoc', ydoc)
  
  // 组件挂载时
  onMounted(() => {
    // 等待数据同步
    persistence.whenSynced.then(() => {
      console.log('数据已与IndexedDB同步')
      value.value = ytext.toString()
    })
  
    // 监听文档变化
    ytext.observe(() => {
      value.value = ytext.toString()
    })
  
    // 监听awareness变化（用户加入/离开/光标移动）
    provider.awareness.on('change', updateCollaborators)
    updateCollaborators() // 初始更新
  
    // 定期更新光标位置
    const cursorUpdateInterval = setInterval(updateCursorPosition, 500)
    
    onUnmounted(() => {
      clearInterval(cursorUpdateInterval)
    })
  })
  
  // 组件卸载时清理
  onUnmounted(() => {
    persistence.destroy()
    provider.destroy()
  })
  </script>
  
  <style scoped>
  .collaborative-editor-container {
    max-width: 800px;
    margin: 0 auto;
    padding: 20px;
    font-family: Arial, sans-serif;
    position: relative;
  }
  
  .user-info {
    margin-bottom: 20px;
    padding: 10px;
    background-color: #f5f5f5;
    border-radius: 4px;
  }
  
  .username {
    font-weight: bold;
    display: flex;
    align-items: center;
    gap: 10px;
  }
  
  .user-avatar, .collaborator-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    object-fit: cover;
  }
  
  .collaborators {
    display: flex;
    gap: 15px;
    margin-bottom: 20px;
    flex-wrap: wrap;
  }
  
  .collaborator {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 5px 10px;
    background-color: #f0f0f0;
    border-radius: 16px;
    font-size: 14px;
  }
  
  .editor-container {
    position: relative;
  }
  
  .editor {
    width: 100%;
    min-height: 300px;
    padding: 15px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 16px;
    line-height: 1.5;
    resize: vertical;
    font-family: monospace;
    white-space: pre;
  }
  
  .editor:focus {
    outline: none;
    border-color: #646cff;
    box-shadow: 0 0 0 2px rgba(100, 108, 255, 0.2);
  }
  
  .cursor-indicator {
    position: absolute;
    width: 2px;
    height: 20px;
    animation: blink 1s infinite;
  }
  
  @keyframes blink {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.3; }
  }
  
  .cursor-label {
    position: absolute;
    top: -24px;
    left: -2px;
    padding: 2px 6px;
    border-radius: 4px;
    color: white;
    font-size: 12px;
    white-space: nowrap;
    pointer-events: none;
  }
  </style>